package cate.game.role.res.guild.po.member;

import cate.common.table.d.GDFunc;
import cate.common.table.d.GDGuild;
import cate.common.table.d.GDMail;
import cate.common.util.GameResult;
import cate.game.GameBody;
import cate.game.event.guild.GuildMemberRemovedEvent;
import cate.game.mail.po.MailBuilder;
import cate.game.role.Role;
import cate.game.role.RoleSnapshot;
import cate.game.role.mail.Mail;
import cate.common.table.guild.GuildGradeRow;
import cate.game.role.res.guild.GuildFuncBase;
import cate.game.role.res.guild.msg.member.GuildMembersResp;
import cate.game.role.res.guild.po.GuildLogDetailPO;
import cate.game.role.res.guild.po.GuildPO;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

@Slf4j
@NoteClass(value = "公会成员管理")
public class GuildMemberPO extends GuildFuncBase {

    @NoteField(value = "公会成员列表")
    public List<GuildMemberDetailPO> list;

    @NoteField(value = "今日踢活跃用户次数")
    public int kickOutNum;

    @NoteField(value = "会长未上线天数超过三天", detail = "ture：超过 false：未超过")
    public boolean expired;

    @NoteField(value = "计时器", detail = "弹劾24小时记录第一次被弹劾的时间")
    public long timer;

    @NoteField(value = "公会弹劾成员列表")
    public List<GuildMemberDetailPO> impeachList;

    @NoteField(value = "公会成员管理日志")
    public GuildMemberLogPO memberLog;


    @Override
    public void initialize(GuildPO guild) {
        super.initialize(guild);
        if (list == null) {
            list = new ArrayList<>();
        }
        list.forEach(a -> a.initialize(guild));
        if (impeachList == null) {
            impeachList = new ArrayList<>();
        }
        if (expired != GDGuild.member.PRESIDENT_EXPIRED_LIMIT) {
            expired = GDGuild.member.PRESIDENT_NO_EXPIRED_LIMIT;
        }
        if (memberLog == null) {
            memberLog = new GuildMemberLogPO();
        }
        memberLog.initialize(guild);
        update();
    }

    public void update() {
        presidentPosCheck();
        presidentOfflineCheck();
    }

    /**
     * 会长身份修正(防止出现多个会长)
     */
    private void presidentPosCheck() {
        GuildPO guild = getFuncDependent().getGuild();
        for (GuildMemberDetailPO detail : list) {
            if (detail.performance.position == GDGuild.position.PRESIDENT
                    && !StringUtils.equals(guild.basic.presidentId, detail.it.uid)) {
                detail.performance.position = GDGuild.position.MEMBER;
            }
            if (StringUtils.equals(guild.basic.presidentId, detail.it.uid)) {
                detail.performance.position = GDGuild.position.PRESIDENT;
                guild.basic.presidentName = detail.it.base.name;
                guild.basic.srvIdOriginPresident = detail.it.base.srvIdOrigin;
            }
        }
    }

    /**
     * 根据唯一ID获取成员
     */
    @JsonIgnore
    public GuildMemberDetailPO getMember(String roleId) {
        for (GuildMemberDetailPO member : list) {
            if (StringUtils.equals(member.it.uid, roleId)) {
                return member;
            }
        }
        return null;
    }

    public synchronized GameResult<Void> addMember(Role role) {
        return addMember(role, GDGuild.position.MEMBER);
    }

    public List<GuildMemberDetailPO> getCopyMembers(){
        return new ArrayList<>(list);
    }

    /**
     * 添加成员
     */
    @JsonIgnore
    public synchronized GameResult<Void> addMember(Role role, byte position) {
        GameResult<Void> r = new GameResult<>();
        GuildPO guild = getFuncDependent().getGuild();
//         判断人数有没有满
        GuildGradeRow row = guild.basic.getRow();
        if (guild.basic.memberNum >= row.memberLimit) {
            //903036
            role.getGame().notice.message(role, 310418, "公会成员已满，尝试加入其他公会吧");
            return r.fail("公会成员已满，尝试加入其他公会吧");
        }
        // 判断成员是否已经在公会中
        for (GuildMemberDetailPO member : list) {
            if (StringUtils.equals(role.getUid(), member.it.uid)) {
                //903037
                role.getGame().notice.message(role, 310419, "该角色已经加入公会");
                return r.fail("该角色已经加入公会");
            }
        }
        // 从role身上读取公会表现信息
        GuildMemberDetailPO member = new GuildMemberDetailPO();
        member.initialize(guild);
        member.read(role);
        member.performance.position = position;
        // 添加成员
        this.list.add(member);
        // 更新成员数量
        guild.basic.memberNum++;
        // 更新公会战力
        guild.updatePower();
        // 在role身上同步公会信息
        role.getRes().guild.uid = guild.uid;
        role.getRes().guild.guildName = guild.basic.guildName;
        role.getRes().guild.joinTime = System.currentTimeMillis();
        // 给新入会的成员发送公会消息
        role.getRes().guild.noticeUpdate();
        guild.noticeUpdate(role);
        // 通知在线玩家有新的公会基本信息
        guild.basic.noticeUpdateAll();
        return r.success();
    }


    /**
     * 查询帮会里所有在线的成员的role
     */
    @JsonIgnore
    public List<Role> getOnlineRole() {
        GuildPO guild = getFuncDependent().getGuild();
        List<Role> result = new ArrayList<>();
        for (GuildMemberDetailPO member : this.list) {
            Role online = guild.game.role.findOnline(member.it.uid);
            if (online != null) {
                result.add(online);
            }
        }
        return result;
    }


    /**
     * 公会成员列表通知
     */
    @JsonIgnore
    public void noticeUpdate(Role role) {
        if (!guildFuncOpenCheck(role)) {
            return;
        }
        role.sendNow(new GuildMembersResp(this));
    }

    public void updateAllMemberData() {
        if (!guildFuncOpenCheck()) {
            return;
        }
        GuildPO guild = getFuncDependent().getGuild();
        list.forEach(member -> member.read(guild.game.role.findOnline(member.it.uid)));
    }

    /**
     * 根据职位获取在线成员的role
     */
    public List<Role> getOnlineRoleByPos(GameBody game, Byte... args) {
        List<GuildMemberDetailPO> tempList = getMemberByPos(args);
        List<Role> result = new ArrayList<>();
        for (GuildMemberDetailPO member : tempList) {
            Role roleOnline = game.role.findOnline(member.it.uid);
            if (roleOnline != null) {
                result.add(roleOnline);
            }
        }
        return result;
    }


    /**
     * 根据职位获取成员信息
     */
    @JsonIgnore
    public List<GuildMemberDetailPO> getMemberByPos(Byte... args) {
        List<GuildMemberDetailPO> data = new ArrayList<>();
        for (GuildMemberDetailPO member : this.list) {
            for (byte position : args) {
                if (member.performance.position == position) {
                    data.add(member);
                    break;
                }
            }
        }
        return data;
    }

    /**
     * 检查会长离线时长超过弹劾限制与否
     */
    public void presidentOfflineCheck() {
        GuildPO guild = getFuncDependent().getGuild();
        GuildMemberDetailPO president = this.getMember(guild.basic.presidentId);
        if (!isActive(president)) {
            expired = GDGuild.member.PRESIDENT_EXPIRED_LIMIT;
        } else {
            expired = GDGuild.member.PRESIDENT_NO_EXPIRED_LIMIT;
        }
    }

    public void tickSelf(GameBody game) {
        update();
        if (timer != GDGuild.member.DEFAULT_TIMER_VALUE &&
                System.currentTimeMillis() - timer > GDGuild.member.AUTO_TRANSFER_DAY * 86400000) {
            autoChangePresident(game);
            clearImpeachStatus();
        }
    }

    /**
     * 弹劾状态清空
     */
    private void clearImpeachStatus() {
        timer = GDGuild.member.DEFAULT_TIMER_VALUE;
        impeachList.clear();
        expired = GDGuild.member.PRESIDENT_NO_EXPIRED_LIMIT;
    }

    /**
     * 会长为机器人的时候换会长
     *
     * @param role role
     */
    public void autoChangePresident(Role role) {
        impeachList.add(getMember(role.getUid()));
        GuildPO guild = getFuncDependent().getGuild();
        autoChangePresident(guild.game);
        clearImpeachStatus();
    }

    /**
     * 会长自动转让检测
     *
     * @param game game
     */
    public synchronized void autoChangePresident(GameBody game) {
        GuildPO guild = getFuncDependent().getGuild();
        GuildMemberDetailPO oldPresident = this.getMember(guild.basic.presidentId);
        GuildMemberDetailPO successor = getSuccessor();
        if (successor != null
                && !StringUtils.equals(guild.basic.presidentId, successor.it.uid)) {
            successor.performance.changePos(GDGuild.position.PRESIDENT);
            guild.basic.presidentId = successor.it.uid;
            guild.basic.presidentName = successor.it.base.name;
            guild.basic.srvIdOriginPresident = successor.it.base.srvIdOrigin;
            // 会长有可能会没有？
            if (oldPresident != null && !oldPresident.it.unreal) {
                log.info("玩家" + oldPresident.it.base.name + "的会长位置被自动移交给" + successor.it.base.name);
                oldPresident.performance.changePos(GDGuild.position.MEMBER);
                // 给全公会玩家发邮件 通知会长转移

                // 您所在公会会长连续超过XX天未上线，会长职务经过弹劾自动转移给XX，恭喜XX成为XX公会的新会长！
                List<Object> params = new ArrayList<>();
                params.add(GDGuild.member.EXPIRED_DAY);
                params.add(successor.it.base.name);
                params.add(successor.it.base.name);
                params.add(guild.basic.guildName);
                Mail mail =
                        new MailBuilder()
                                .setContentId(GDMail.Tid.PRESIDENT_TRANSFER)
                                .setParamList(params)
                                .build();
                for (GuildMemberDetailPO detailPO : this.list) {
                    game.mail.send(detailPO.it.uid, mail.copy());
                }
            }
            guild.basic.noticeUpdateAll();
            // 公会日志
            memberLog.addLog(game,
                    new GuildLogDetailPO(
                            GDGuild.log.APPOINT_PRESIDENT, successor.it.base.name));
            // 如果是机器人则自动离开公会
            if (oldPresident != null && oldPresident.it.unreal) {
                // 从公会成员列表中移除机器人
                this.removeMember(guild.game, oldPresident.it.uid);
                // 篡改公会创建时间
                guild.basic.createTime = System.currentTimeMillis();
                guild.noticeOnline(guild::noticeUpdate);
            }
        }
    }


    /**
     * 找一个公会接班人
     */
    private GuildMemberDetailPO getSuccessor() {
        if (impeachList.isEmpty()) {
            return null;
        }
        // 先移除异常弹劾人
        impeachList.removeIf(a -> getMember(a.it.uid) == null);
        // 按照职位、贡献、战力排序
        impeachList.sort(
                Comparator.comparing((GuildMemberDetailPO a) -> -a.performance.position)
                        .thenComparing(a -> -a.performance.activeTotal)
                        .thenComparing(a -> -a.it.base.power));
        return impeachList.get(0);
    }

    /**
     * 判断公会成员是否活跃
     */
    private boolean isActive(GuildMemberDetailPO member) {
        if (member == null) {
            return false;
        }
        long pastTime = System.currentTimeMillis() - member.it.activeTime;
        return pastTime <= GDGuild.member.EXPIRED_DAY * 86400000L;
    }

    public void onDaySpan() {
        presidentPosCheck();
        list.forEach(GuildMemberDetailPO::onDaySpan);
        this.kickOutNum = 0;
    }

    /**
     * 踢出成员
     */
    public void kickOutMember(Role role, String uId) {
        if (!guildFuncOpenCheck(role)) {
            return;
        }
        // 成员信息检测
        GuildMemberDetailPO member = getMember(uId);
        if (member == null) {
            role.getGame().notice.message(role, "成员不存在");
            return;
        }
        if (member.performance.position >= role.getRes().guild.getPos()) {
            role.getGame().notice.message(role, "无法踢出该成员");
            return;
        }

        //上次捐献在一天内的视为活跃用户
        boolean active = false;
        GuildPO guild = getFuncDependent().getGuild();
        if (member.performance.lastDonateId == null || member.performance.lastDonateId.equals(guild.uid)) {
            active = System.currentTimeMillis() - member.performance.lastDonateTime <= 24 * 60 * 60 * 1000;
        }

        if (active && GDGuild.basic.KICK_OUT_NUM_MAX > 0 && kickOutNum >= GDGuild.basic.KICK_OUT_NUM_MAX) {
            role.getGame().notice.message(role, "无法踢出该成员");
            return;
        }
        // 从公会成员列表中移除成员
        removeMember(role.getGame(), uId);
        if (active) {
            kickOutNum++;
        }

        // 向操作者更新成员列表信息
        noticeUpdate(role);
        // 记录公会日志
        memberLog.addLog(
                role.getGame(),
                new GuildLogDetailPO(
                        GDGuild.log.KICK_OUT_MEMBER, member.it.base.name, role.getBase().name));
        role.getGame().notice.message(role, "成员踢出成功");
    }


    /**
     * 移除成员
     */
    @JsonIgnore
    public synchronized void removeMember(GameBody game, String uid) {
        Iterator<GuildMemberDetailPO> it = list.iterator();
        Role roleRead = game.role.getRole(uid, true);
        GuildPO guild = getFuncDependent().getGuild();
        GuildMemberRemovedEvent memberRemoved = new GuildMemberRemovedEvent(roleRead, guild);

        // TODO: 2022/9/30 弹劾列表清除,会长自动转让逻辑中添加无人弹劾

        while (it.hasNext()) {
            GuildMemberDetailPO item = it.next();
            if (StringUtils.equals(uid, item.it.uid)) {
                memberRemoved.setPos(item.performance.position);
                it.remove();
                guild.basic.memberNum--;
                // 更新公会战力
                guild.updatePower();
                break;
            }
        }
        Iterator<GuildMemberDetailPO> impeachIt = list.iterator();

        while (impeachIt.hasNext()) {
            GuildMemberDetailPO item = impeachIt.next();
            if (StringUtils.equals(uid, item.it.uid)) {
                impeachIt.remove();
                break;
            }
        }

        // 如果这个成员在线，则通知他被踢了
        Role role = game.role.findOnline(uid);
        if (role != null) {
            role.getRes().guild.clear();
            role.getRes().guild.noticeUpdate();
        } else {
            guild.game.res.guild.data.kickOutMap.put(uid, System.currentTimeMillis());
        }
        // 通知在线玩家有新的公会基本信息
        guild.basic.noticeUpdateAll();

        if (roleRead != null) {
            publishEvent(guild.game, memberRemoved);
        }

    }

    /**
     * 三天不上线的的弹劾加入impeachList
     *
     * @param role role
     */
    public void impeachPresident(Role role) {
        if (!guildFuncOpenCheck(role)) {
            return;
        }
        presidentOfflineCheck();
        if (!expired) {
            role.getGame().notice.message(role, 310423, "会长离线时间不足三天，不能弹劾");
            return;
        }
        if (timer == GDGuild.member.DEFAULT_TIMER_VALUE) {
            timer = System.currentTimeMillis();
        }
        impeachList.add(getMember(role.getUid()));
        this.noticeUpdate(role);
        role.getGame().notice.message(role, 310424, "弹劾成功");
    }

    /**
     * 任命新会长
     */
    public void appointPresident(Role role, String uid) {
        if (!guildFuncOpenCheck(role)) {
            return;
        }
        GuildPO guild = getFuncDependent().getGuild();
        if (role.getRes().guild.getPos() != GDGuild.position.PRESIDENT) {
            role.getGame().notice.message(role, 310425, "仅有会长可以任命新会长");
            return;
        }
        // 新会长信息检测
        GuildMemberDetailPO changeMember = getMember(uid);
        if (changeMember == null) {
            role.getGame().notice.message(role, 310420, "成员不存在");
            return;
        }
        // 在成员列表中修改新老会长的职务
        role.getRes().guild.getMember().performance.changePos(GDGuild.position.MEMBER);

        changeMember.performance.changePos(GDGuild.position.PRESIDENT);
        // 通知操作者新的成员列表
        noticeUpdate(role);
        // 通知被操作者新的成员列表
        if (guild.game.role.findOnline(uid) != null) {
            noticeUpdate(guild.game.role.findOnline(uid));
            //通知被操作者自己的公会信息
            guild.game.role.findOnline(uid).getRes().guild.noticeUpdate();
        }

        // 公会基本信息更新，并且通知在线成员
        guild.basic.presidentId = changeMember.it.uid;
        guild.basic.presidentName = changeMember.it.base.name;
        guild.basic.srvIdOriginPresident = changeMember.it.base.srvIdOrigin;
        guild.basic.noticeUpdateAll();
        // 记录公会日志
        memberLog.addLog(role.getGame(),
                new GuildLogDetailPO(GDGuild.log.APPOINT_PRESIDENT, changeMember.it.base.name));
        // 公会聊天频道
        role.getGame().notice.message(role, 310426, "会长转让成功");

    }

    /**
     * 任命副会长
     */
    public void appointVicePresident(Role role, String uid) {
        if (!guildFuncOpenCheck(role)) {
            return;
        }
        if (role.getRes().guild.getPos() != GDGuild.position.PRESIDENT) {
            role.getGame().notice.message(role, 310427, "仅有会长可以任命副会长");
            return;
        }
        GuildPO guild = getFuncDependent().guild;
        // 副会长信息检测
        GuildMemberDetailPO changeMember = getMember(uid);
        if (changeMember == null) {
            role.getGame().notice.message(role, 310420, "成员不存在");
            return;
        }
        // 当前公会等级的副会长数量限制检测
        if (getMemberByPos(GDGuild.position.VICE_PRESIDENT).size()
                >= guild.basic.getRow().viceNum) {
            role.getGame().notice.message(role, 310428, "无法任命更多的副会长");
            return;
        }
        // 职务变更
        changeMember.performance.changePos(GDGuild.position.VICE_PRESIDENT);
        // 通知会长新的成员列表信息
        noticeUpdate(role);
        // 通知被更新的成员列表信息
        if (guild.game.role.findOnline(uid) != null) {
            noticeUpdate(guild.game.role.findOnline(uid));
            //通知被操作者自己的公会信息
            guild.game.role.findOnline(uid).getRes().guild.noticeUpdate();
        }

        // 记录公会日志
        memberLog.addLog(role.getGame(),
                new GuildLogDetailPO(
                        GDGuild.log.APPOINT_VICE_PRESIDENT, changeMember.it.base.name));
        // 公会频道消息
        role.getGame().notice.message(role, 310429, "副会长任命成功");
    }

    /**
     * 解雇副会长
     */
    public void dismissVicePresident(Role role, String uid) {
        if (!guildFuncOpenCheck(role)) {
            return;
        }
        if (role.getRes().guild.getPos() != GDGuild.position.PRESIDENT) {
            role.getGame().notice.message(role, 310430, "仅有会长可以解雇副会长");
            return;
        }
        GuildPO guild = getFuncDependent().guild;

        // 副会长信息检测
        GuildMemberDetailPO changeMember = getMember(uid);
        if (changeMember == null) {
            role.getGame().notice.message(role, 310420, "成员不存在");
            return;
        }
        // 修改副会长的职务
        changeMember.performance.changePos(GDGuild.position.MEMBER);
        // 通知会长成员列表信息更新
        noticeUpdate(role);
        // 通知被更新的成员列表信息
        if (guild.game.role.findOnline(uid) != null) {
            noticeUpdate(guild.game.role.findOnline(uid));
            //通知被操作者自己的公会信息
            guild.game.role.findOnline(uid).getRes().guild.noticeUpdate();
        }

        // 记录公会日志
        memberLog.addLog(role.getGame(),
                new GuildLogDetailPO(
                        GDGuild.log.DISMISS_VICE_PRESIDENT, changeMember.it.base.name));
        role.getGame().notice.message(role, 310431, "副会长罢免成功");
    }

    /**
     * 退出公会
     */
    public void exitGuild(Role role) {
        if (!guildFuncOpenCheck(role)) {
            return;
        }
        if (role.getRes().guild.getPos() == GDGuild.position.PRESIDENT) {
            role.getGame().notice.message(role, 310432, "会长无法退出公会");
            return;
        }

        // 从公会成员列表中移除成员
        removeMember(role.getGame(), role.getUid());
        // 记录公会日志
        memberLog.addLog(role.getGame(), new GuildLogDetailPO(GDGuild.log.QUIT_GUILD, role.getBase().name));
        // 公会频道
        synSnapShot(role.getGame());
        role.getGame().notice.message(role, 310433, "退出公会成功");
        role.getBase().updatePower();
    }

    /**
     * 同步成员快照
     */
    public void synSnapShot(GameBody game) {
        list.forEach(a -> a.it.sync(game));
        GuildPO guild = getFuncDependent().guild;
        guild.updatePower();
    }

    /**
     * 任命长老
     */
    public void appointPresbyter(Role role, String uid) {
        if (!guildFuncOpenCheck(role)) {
            return;
        }
        if (role.getRes().guild.getPos() != GDGuild.position.PRESIDENT &&
                role.getRes().guild.getPos() != GDGuild.position.VICE_PRESIDENT) {
            role.getGame().notice.message(role, 310434, "仅有会长和副会长可以任命长老");
            return;
        }
        // 长老信息检测
        GuildMemberDetailPO changeMember = getMember(uid);
        GuildPO guild = getFuncDependent().guild;

        if (changeMember == null) {
            role.getGame().notice.message(role, "成员不存在");
            return;
        }
        // 当前公会等级的长老数量限制检测
        if (getMemberByPos(GDGuild.position.PRESBYTER).size()
                >= guild.basic.getRow().presbyterNum) {
            role.getGame().notice.message(role, "无法任命更多的长老");
            return;
        }
        // 职务变更
        changeMember.performance.changePos(GDGuild.position.PRESBYTER);
        // 通知会长新的成员列表信息
        noticeUpdate(role);
        // 通知被更新的成员列表信息
        if (guild.game.role.findOnline(uid) != null) {
            noticeUpdate(guild.game.role.findOnline(uid));
            //通知被操作者自己的公会信息
            guild.game.role.findOnline(uid).getRes().guild.noticeUpdate();
        }

        // 记录公会日志
        memberLog.addLog(role.getGame(),
                new GuildLogDetailPO(
                        GDGuild.log.APPOINT_PRESBYTER, changeMember.it.base.name));
        // 公会频道消息
        role.getGame().notice.message(role, "长老任命成功");
    }


    /**
     * 解雇长老
     */
    public void dismissPresbyter(Role role, String uid) {
        if (!guildFuncOpenCheck(role)) {
            return;
        }
        if (role.getRes().guild.getPos() != GDGuild.position.PRESIDENT && role.getRes().guild.getPos() != GDGuild.position.VICE_PRESIDENT) {
            role.getGame().notice.message(role, "仅有会长和副会长可以解雇长老");
            return;
        }
        GuildPO guild = getFuncDependent().guild;

        // 长老信息检测
        GuildMemberDetailPO changeMember = getMember(uid);
        if (changeMember == null) {
            role.getGame().notice.message(role, "成员不存在");
            return;
        }
        // 修改长老的职务
        changeMember.performance.changePos(GDGuild.position.MEMBER);
        // 通知会长成员列表信息更新
        noticeUpdate(role);
        // 通知被更新的成员列表信息
        if (guild.game.role.findOnline(uid) != null) {
            noticeUpdate(guild.game.role.findOnline(uid));
            //通知被操作者自己的公会信息
            guild.game.role.findOnline(uid).getRes().guild.noticeUpdate();
        }

        // 记录公会日志
        memberLog.addLog(role.getGame(),
                new GuildLogDetailPO(
                        GDGuild.log.DISMISS_PRESBYTER, changeMember.it.base.name));
        // 公会聊天频道
        role.getGame().notice.message(role, "长老罢免成功");
    }

    public void addMember(RoleSnapshot snap) {
        // 从role身上读取公会表现信息
        GuildPO guild = getFuncDependent().guild;

        GuildMemberDetailPO member = new GuildMemberDetailPO();
        member.initialize(guild);
        member.read(snap);
        // 添加成员
        this.list.add(member);
        // 更新成员数量
        guild.basic.memberNum++;
    }

    @Override
    public int getFuncId() {
        return GDFunc.GuildFunc.MEMBER;
    }

}
